package com.skplanet.rade.service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.encoding.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.skplanet.rade.dao.TagDAO;
import com.skplanet.rade.dao.UserDAO;
import com.skplanet.rade.dao.UserTagDAO;
import com.skplanet.rade.domain.Story;
import com.skplanet.rade.domain.StoryTag;
import com.skplanet.rade.domain.Tag;
import com.skplanet.rade.domain.User;
import com.skplanet.rade.domain.UserTag;
import com.skplanet.rade.util.StringUtils;

@Service(value = "userService")
@Transactional
public class UserService {

	@Autowired
	private UserDAO userDAO;

	@Autowired
	private UserTagDAO userTagDAO;

	@Autowired
	private TagDAO tagDAO;

	@Autowired
	private TagService tagService;

	@Autowired
	private UserTagService userTagService;

	@Autowired
	private PasswordEncoder passwordEncoder;

	// user Row 추가
	@Transactional
	public void addUser(String email, String password, String nickname,
			String tagKeyword0, String tagKeyword1, String tagKeyword2) {

		User user = new User();
		user.setEmail(email);
		String salt = StringUtils.genRandomString(10);
		user.setSalt(salt);
		user.setPassword(passwordEncoder.encodePassword(password, salt));
		user.setNickname(nickname);
		user.setAuthority("ROLE_USER");

		if (tagKeyword0 != null) {
			addUserTag(user, tagKeyword0);
		}
		if (tagKeyword1 != null) {
			addUserTag(user, tagKeyword1);
		}
		if (tagKeyword2 != null) {
			addUserTag(user, tagKeyword2);
		}

		userDAO.save(user);
	}

	@Transactional
	public User initUser(String email, String password, String nickname) {
		User user = new User();
		user.setEmail(email);
		String salt = StringUtils.genRandomString(10);
		user.setSalt(salt);
		user.setPassword(passwordEncoder.encodePassword(password, salt));
		user.setNickname(nickname);
		user.setAuthority("ROLE_USER");

		return user;
	}

	@Transactional
	public void addUserTag(User user, String keyword0, String keyword1,
			String keyword2) {
		addUserTag(user, keyword0);
		addUserTag(user, keyword1);
		addUserTag(user, keyword2);
	}

	// Tag 테이블에 Row를 추가/업데이트하고, user 객체에 UserTag 추가
	@Transactional
	public void addUserTag(User user, String keyword) {
		/*
		 * UserTag userTag = new UserTag(); userTag.setKeyword(keyword);
		 * userTag.addCount();
		 * 
		 * Tag tag = tagService.addUserTag(userTag); userTag.setTag(tag);
		 * tagService.addTag(tag);
		 * 
		 * userTag.setUser(user); user.addUserTag(userTag);
		 */
		UserTag userTag = new UserTag();
		userTag.setKeyword(keyword);
		userTag.addCount();

		Tag newTag = tagDAO.findUniqByObject("keyword", keyword);
		if (newTag == null) {
			newTag = new Tag();
			newTag.setKeyword(userTag.getKeyword());

			newTag.adduCount();
			newTag.addUserTag(userTag);

			Tag tag = newTag;

			userTag.setTag(tag);
			tagDAO.save(tag);
		} else {
			newTag.adduCount();
			newTag.addUserTag(userTag);

			Tag tag = newTag;

			userTag.setTag(tag);
			tagDAO.update(tag);
		}

		userTag.setUser(user);
		user.addUserTag(userTag);
	}

	// user Row 업데이트
	@Transactional
	public void updateUser(User user) {
		user.setUpdateDate(new Date());
		userDAO.update(user);
	}

	@Transactional
	public void addUser(User user) {
		userDAO.save(user);
	}

	// userId를 가진 Row 반환
	@Transactional(readOnly = true)
	public User select(String userId) {
		User user = userDAO.select(userId);
		return user;
	}

	// userId를 가진 Row 삭제
	@Transactional
	public void deleteUser(long userId) {
		userDAO.delete(new User(userId));
	}

	// email을 가진 Row의 userId 반환
	@Transactional(readOnly = true)
	public String getUserIdFromEmail(String email) {
		return (String) userDAO.findColumnByObject("id", "email", email);
	}

	// email을 가진 Row 반환
	@Transactional(readOnly = true)
	public User getUserFromEmail(String email) {
		return (User) userDAO.findUniqByObject("email", email);
	}

	// 모든 Row 반환
	@Transactional(readOnly = true)
	public List<User> getAllUser() {
		return userDAO.getAll();
	}

	// nickname을 가진 Row 반환
	@Transactional(readOnly = true)
	public User getUserFromNickname(String nickname) {
		return (User) userDAO.findUniqByObject("nickname", nickname);
	}

	// email을 가진 Row 확인
	@Transactional(readOnly = true)
	public boolean emailExists(String email) {
		return userDAO.rowExists("email", email);
	}

	// nickname을 가진 Row 확인
	@Transactional(readOnly = true)
	public boolean nicknameExists(String nickname) {
		return userDAO.rowExists("nickname", nickname);
	}

	// user Row의 password가 currentPasword인지 확인
	@Transactional
	public boolean checkEqualsPassword(User user, String currentPassword) {
		String repositoryPassword = user.getPassword();
		String encodedPassword = passwordEncoder.encodePassword(
				currentPassword, user.getSalt());
		return repositoryPassword.equals(encodedPassword);
	}

	// Tag 테이블에 Row를 추가하고, user 객체에 UserTag 추가
	@Transactional
	public void addUserTagWhenStory(User user, String keyword) {
		UserTag userTag = new UserTag();
		userTag.setKeyword(keyword);

		// Tag 테이블에 Row 추가

		Tag tag = tagService.addUserTag(userTag);

		userTag.addCount();
		userTag.setTag(tag);
		userTag.setUser(user);

		// user 객체에 userTag 추가
		user.addUserTag(userTag);
	}

	// Story 테이블에 Row를 추가하고, user 객체에 Story 추가
	@Transactional
	public void addStory(User user, Story story) {
		List<StoryTag> stList = story.getStoryTags();

		for (int i = 0; i < stList.size(); i++) {
			addUserTagWhenStory(user, stList.get(i).getKeyword());
		}
	}

	// user Row의 password 업데이트
	@Transactional
	public void changePassword(User user, String password) {
		user.setPassword(passwordEncoder.encodePassword(password,
				user.getSalt()));
		userDAO.update(user);
	}

	// email 유저의 UserTag Top N개를 반환하는 메소드
	@Transactional
	public List<UserTag> getNUserTagListFromUser(User user, int n) {
		List<UserTag> userTagList = new ArrayList<UserTag>();
		List<UserTag> topNUserTagList = new ArrayList<UserTag>();

		userTagList = user.getUserTags();

		Collections.sort(userTagList, UserTag.getUsertagcomparator());

		for (int i = 0; i < n && i < userTagList.size(); i++) {
			topNUserTagList.add(userTagList.get(i));
		}

		return topNUserTagList;
	}
}